home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1994
/
MacHack 1994.toast
/
MacHack™94
/
Talks & Papers
/
Timothy Knox
/
yerk 3.66
/
Module source
/
Decompile
< prev
next >
Wrap
Text File
|
1994-06-24
|
18KB
|
590 lines
\ Yerk Disassembler
\ 1/16/86 cdn Initial version
\ 1/20/86 cdn Handle named input parameters and local variables
\ 2/24/86 cdn Added detection of Immediate words
\ Added RANGEOF
\ 6/01/86 cdn Added (++>), (EX>), (TRAP), (DEFER), (JMP), COMPILE
\ 6/02/86 cdn Added deClass, deObj, deModule, etc…
\ 8/11/86 cdn Added multiple cfa recognition
\ 8/25/86 cdn Added method decompilation
\ 6/29/87 rfl Added the first three cases to handle floats
\ 12/17/87 rfl Fixed .num to show signs
\ 1/11/90 rfl Fixed ?isobj,?isclass,?ismod,?isvect,.32-bit etc. for protection
\ against invalid RAM
\ 3/14/90 rfl nhash now wordcol; took out ?isobj since now in Class
\ 10/03/90 rfl added protection for lit numbers out of app range
\ 10/26/90 rfl changed /module to |module so can decompile words with '/' in them
\ 12/16/90 rfl added offCol instead of old ordered-col
\ 3/29/91 rfl fixed slight bug setting 0 -> #p in decol
\ 10/26/91 rfl undid a reserve back to allot in name/hash
\ 2/25/92 rfl fixed super/self problem with decompiling a class method
\ 5/14/93 rfl now decompiles vect, value, and sysvec contents too.
\ 6/17/93 rfl fixed another super/self problem when de' a method
\ 6/22/93 rfl added support for float named input and local vars
\ 7/16/93 rfl after 3.64 release, redefined 'inapprange?' to use heapbot and top
\ 7/21/93 rfl added inapprange? to 32-bit
\ 12/29/93 rfl no longer crashes on mcode
\ de' will decompile colon definitions and methods of classes; follow with a
\ slash-module name to decompile module code. Named stack parms and local vars
\ are indicated by a curly bracket syntax like the one used to compile them,
\ however their actual names are no longer known after compilation so symbolic
\ names parmN & varN are shown. Method selectors are also unavailable after
\ compilation since they are hashed, so the common sequence: meth: obj
\ decompiles as: ???: obj. Methods bound to ivars within class definitions
\ are shown by the offset of the ivar data within the object. eg: ???: 12
\ Anything completely unrecognized will display as ¿¿¿
\
\ "deflgs" bits:
\ 0 - print absolute address of each item
\ 1 - print relative address of each item
\ 2 - print offset of each item
\ 3 - display super class data
\ 4 - display nested ivar stuctures
\ 5 - display indexed data
:module deMod
0 value tab
: indent tab 4* out - 0 max spaces ;
: .bld 1 tFace ; \ print in bold
: .exp 64 tFace ; \ print in expanded
: .nor 0 tFace ; \ revert to normal mode
: .hash .bld ." hash:" . .nor ;
\ : sign rot 0< IF 45 hold THEN ;
\ ( val -- )
: .num dup abs 0 <# #s sign #> type ;
0 value start
\ Print address and/or offset of datum
: .addr { addr -- }
.bld
deflgs 01 and IF addr +base .num ascii : emit THEN
deflgs 02 and IF addr .num ascii : emit THEN
deflgs 04 and IF addr start - .num ascii : emit THEN
.nor ;
: NewL ?pause
CR dup .addr
0 -> out indent ;
: ?NewL
out tab 4* - 0> IF NewL THEN ;
\ ( addr -- addr' ) print "parmN" or "varN"
: .p/v
dup @ >name 3+ c@ dup 48 - mp0 < \ mp0 is a peek at deComp's "#p" var
IF ." parm" ELSE ." var" THEN
emit space 4+ ;
\ ( addr -- addr' ) print "parmN" or "varN"
: .%p/v
dup @ >name 4+ c@ dup 48 - mp0 < \ mp0 is a peek at deComp's "#p" var
IF ." %parm" ELSE ." %var" THEN
emit space 4+ ;
0 value nflgs
\ ( pfa -- ) print name of definition and save name field flags
: .nfa nfa dup id. c@ -> nflgs ;
:CLASS wArray <Super Object 2 <Indexed
:M AT: ?idx ^Elem w@ ;M
:M TO: ?idx ^Elem w! ;M
;CLASS
:CLASS wordCol <Super wArray
Int Size \ # elements in list
\ ( -- curSize ) Return #elements currently in list
:M SIZE: Get: Size ;M
\ ( val -- ) Add value to end of list
:M ADD: Get: Size limit >=
classErr" 137 Get: size To: Self
1 +: Size ;M
\ ( val -- ind t OR f) Find a value in an OC
:M INDEXOF: 0 swap Get: Size 0
DO i (^elem) w@
over = IF 2drop i 1 1 leave THEN
LOOP drop ;M
;CLASS
:CLASS OffArray <super wordCol
var pointer
:M init: ( addr --) put: pointer ;M
:M at: ( ind -- addr) at: super get: pointer + ;M
:M add: ( addr --) get: pointer - add: super ;M
;CLASS
425 WordCol nHash
425 OffArray hName
: name/hash here init: hName
new: loadFile
" name/hash" name: topFile
openReadOnly: topFile IF ." No name/hash table available" exit THEN
BEGIN
tib 128 expect: topFile 0=
WHILE
bytesRead: topFile 1-
tib over here >str255 here c@ >uc
here hash add: nHash
here add: hName
1+ allot
REPEAT
remove: loadFile
;
name/hash
\ ( val -- )
: .mName
indexOf: nhash
IF at: hName count type space
ELSE ." ???: " THEN ;
: inAppRange? ( addr -- addr b) dup heapBot heapTop within ;
\ ( pfa #parms -- ) Decompile cfas starting from pfa
: deComp { #p \ ;? cf? -- } \ #p number of parms, ;? end of defintion flag
0 -> ;?
1 ++> tab indent
BEGIN ( addr )
dup @
CASE ( addr cfa )
'c flit OF 4+ dup print: float 10 + ENDOF
'c killfargs OF ." KillFargs" 6 + ENDOF
'c !fp(ip) OF ." -> " 4+ dup w@ 8 - 4 / $ 30 + ." %parm" emit 2+ space ENDOF
'c +fp(ip) OF ." ++> " 4+ dup w@ 8 - 4 / $ 30 + ." %parm" emit 2+ space ENDOF
'c lit OF 4+ dup @
over 4+ @ dup 'c trap = swap 'c (fdos) = or
IF ." $" .h
ELSE inAppRange?
IF ?cfa
IF ." 'c " >name id.
ELSE dup cfa ?cfa
IF drop ." ' " nfa id.
ELSE drop .num space
THEN
THEN
ELSE .
THEN
THEN 4+ ENDOF
'c wlit OF 4+ dup w@
over 2+ @ dup 'c trap = swap 'c (fdos) = or
IF ." $" .h
ELSE dup cfa inAppRange?
IF ?cfa
IF drop ." ' " nfa id.
ELSE drop .num space
THEN
ELSE .
THEN
THEN 2+ ENDOF
'c wlitw OF 4+ ." w" dup w@ . 2+ ENDOF
'c (lits) OF 4+ ?NewL dup w@ ." <[" dup . ." ]> 'cfas "
swap 2+ swap 0
DO dup @ >name id. 4+ LOOP ENDOF
'c (trap) OF 4+ ascii $ emit
base >R hex
dup w@ . ." Trap " 2+
R> -> base ENDOF
'c [trap] OF 4+ ascii $ emit
base >R hex
dup w@ . ." Trap " 12 +
R> -> base ENDOF
'c (defer) OF 4+ dup w@ .mName ." [ ] " 2+ ENDOF
'c (classerr") OF 4+ ." ClassErr" ascii " emit
dup w@ . 2+ ENDOF
'c (.rAbort) OF 4+ ." ?error"
dup w@ . 2+ ENDOF
'c (.rStr) OF 4+ ." msg#"
dup w@ . 2+ ENDOF
'c (.tStr) OF 4+ ." type#"
dup w@ . 2+ ENDOF
'c compile OF 4+ ." Compile " dup @ >name id. 4+ ENDOF
'c branch OF 4+ ." Branch:" dup @ dup .
over + .addr 4+ NewL ENDOF
'c 0branch OF 4+ ." 0Branch:" dup @ dup .
over + .addr 4+ NewL ENDOF
'c (do) OF 8+ ?NewL ." DO " 1 ++> tab NewL ENDOF
'c (loop) OF 8+ -1 ++> tab ?NewL ." LOOP " ENDOF
'c (loop+) OF 8+ -1 ++> tab ?NewL ." +LOOP " ENDOF
'c (of) OF 8+ ." OF " ENDOF
'c (rof) OF 8+ ." RANGEOF " ENDOF
'c (select) OF 4+ ?NewL ." Select{" NewL
@ dup dup dup @ - 4 / 1- 0
DO i . ." is{ " 4- dup @ #p deComp
." }end" NewL
LOOP ." default{ "
4- @ #p deComp
?NewL ." }Select" 4+ NewL ENDOF
'c (.") OF 4+ ascii . emit ascii " emit space
count 2dup type ascii " emit space
+ align ENDOF
'c (lit") OF 4+ ascii " emit space
count 2dup type ascii " emit space
+ align ENDOF
'c (ab") OF 4+ ." Abort" ascii " emit space
count 2dup type ascii " emit space
+ align ENDOF
'c (al") OF 4+ ." Alert" ascii " emit space
count 2dup type ascii " emit space
+ align ENDOF
'c (disp) OF 4+ ." Dispose> " dup @ 8- nfa id. 4+ ENDOF
'c (mdisp) OF 4+ ." Dispose> " dup w@ dup #p <
IF ." parm" ELSE ." var" THEN
48 + emit space 2+ ENDOF
'c (be) OF ." Become " 4+ ENDOF
'c (semip) OF drop 1 -> ;? ENDOF
'c (jmp) OF 4+ @ .exp ." ( Forward referenced )"
.nor NewL ENDOF
'c ;s OF drop 1 -> ;? ENDOF
'c (;m) OF drop 1 -> ;? ENDOF
'c (;code) OF drop CR ." (;CODE) " 1 -> ;? ENDOF
'c (,code) OF drop CR ." BUILD " 1 -> ;? ENDOF
'c header OF 10 + dup 2- w@ 4 / 0
DO NewL .exp i .num ." cfa: " .nor
NewL dup @ 10 + 0 deComp CR 4+
LOOP drop 1 -> ;? ENDOF
'c @fp0 OF .%p/v ENDOF
'c @fp1 OF .%p/v ENDOF
'c @fp2 OF .%p/v ENDOF
'c @fp3 OF .%p/v ENDOF
'c @fp4 OF .%p/v ENDOF
'c @fp5 OF .%p/v ENDOF
'c mp0 OF .p/v ENDOF
'c mp1 OF .p/v ENDOF
'c mp2 OF .p/v ENDOF
'c mp3 OF .p/v ENDOF
'c mp4 OF .p/v ENDOF
'c mp5 OF .p/v ENDOF
'c ms0 OF ." -> " .p/v ENDOF
'c ms1 OF ." -> " .p/v ENDOF
'c ms2 OF ." -> " .p/v ENDOF
'c ms3 OF ." -> " .p/v ENDOF
'c ms4 OF ." -> " .p/v ENDOF
'c ms5 OF ." -> " .p/v ENDOF
'c (++>) OF 4+ dup w@ 8- 4 / dup #p < ." ++> "
IF ." parm" ELSE ." var" THEN
48 + emit space 2+ ENDOF
'c (ex>) OF 4+ dup w@ 8- 4 / dup #p < ." exec> "
IF ." parm" ELSE ." var" THEN
48 + emit space 2+ ENDOF
\ OTHERWISE
dup >body ?isObj \ normal early bound method?
IF drop ( addr cfa )
over 4+ @ @ ' m0cfa =
IF over 4+ @ 6 - w@ .mName >name id. 8+
deflgs 07 and IF dup 4- @ 6 - w@ .hash THEN
ELSE >name id. 4+ THEN
ELSE drop ( addr cfa )
dup @ ' m1cfa = \ method bound to a private ivar?
IF 10 - w@ .mName 4+
dup w@ 65535 over = \ check for self/super ref
IF drop dup 4- @ start <
IF ." super" ELSE ." self" THEN
ELSE .num THEN space 2+
deflgs 07 and IF dup 6 - @ 10 - w@ .hash THEN
ELSE ( addr cfa )
dup @ ' m0cfa = \ method bound to a class
IF dup 6 - w@ .mName
latest BEGIN 2dup < WHILE pfa lfa @ REPEAT id. drop
4+
ELSE ( addr cfa )
?cfa \ ultimately, this is the usual case
IF >name dup id. n>count " INLINE" s=
IF 4+ BEGIN dup w@ dup $ 49fa <>
WHILE ascii $ emit .h 2+
out 60 > IF NewL THEN
REPEAT
drop 4+
THEN
ELSE 1 -> cf? 9 1
DO cfa ?cfa \ check for nth cfa
IF dup @ >R valCode R = vectCode R = or
fvalCode R = or svCode R> = or
IF i 1 = IF ." ++> " ELSE ." -> " THEN
ELSE 48 i+ emit 45 emit THEN
>name id. 0 -> cf? leave
THEN
LOOP
cf? IF drop ." ¿¿¿ " THEN \ all decomp failed
THEN
4+
THEN
THEN
THEN
dup \ for consumption by endcase
ENDCASE
deflgs 07 and \ print address and/or offset?
IF
NewL \ new line for every word
ELSE
out 60 > IF NewL THEN
THEN
;? UNTIL
nflgs $ 40 and IF ." Immediate" THEN
-1 ++> tab
;
0 value floatpos
: isFloatP/V ( pos --) floatPos and IF ascii % emit THEN ;
\ ( pfa -- ) decompile a definition; may have named stack
: deCol { myPfa \ amt #p -- } \ #p number of parms
0 -> #p
myPfa c@ \ Does definition has named stack or local vars
IF ." { "
myPfa c@ -> amt \ get the total number of parms and vars
myPfa 1+ c@ -> floatPos \ get position of any floats
amt $ F and -> #p \ look at parms first
#p 0 DO i 1+ isFloatP/V ." parm" 48 i+ emit space LOOP
amt 4 >> -dup
IF ascii \ emit space 0 DO 1 #p i+ << isFloatP/V ." var" 48 #p + i+ emit space LOOP THEN
." -- }" myPfa 2+ -> myPfa
THEN
NewL myPfa #p deComp ;
: NxtL ?pause
CR 0 -> out indent ;
\ ( pfa -- ) decompile a class definition
: deClass { ^class \ k -- } CR
0 -> k 1 -> tab
^class mfa @ \ get starting addresses of method
BEGIN dup ^class >
WHILE 1 ++> k dup 2+ @
REPEAT drop
." :CLASS " ^class nfa id.
." <Super " ^class 22 + @ nfa id.
^class 20 + w@ -dup IF . ." <Indexed" THEN CR
^class 18 + w@ NxtL .exp ." (" . ." Bytes )" .nor CR
k 0 DO
NewL ." :M " dup w@ .mName 10 + dup @
over 4+ = IF drop ." is an MCode definition" ELSE 4+ deCol THEN
NewL ." ;M" CR
LOOP
CR ." ;CLASS"
;
0 value odata
: .) ascii ) emit ;
: .( .addr ascii ( emit ;
: .32-bit
dup . inAppRange?
IF ?cfa
IF >name id. ELSE drop THEN
ELSE drop
THEN ;
\ ( length -- ) display a fundamental datum from the object
: .odata { w -- }
odata .(
w CASE
1 OF odata c@ . ENDOF
2 OF odata w@ . ENDOF
4 OF odata @ .32-bit ENDOF
\ OTHERWISE
w . ." Bytes " \ if not 1, 2 or 3; just tell how many bytes there are
ENDCASE
.)
w ++> odata
;
\ display indexed data cells with their indices
: .idata { \ width -- }
odata w@ -> width 4 ++> odata \ get width and skip indexed header
odata 2- w@ 0
DO NxtL
i . width .odata \ print the contents of each element
LOOP
;
Forward .struct
\ display contents of ivar
: .ivars { lastNFA 1stNFA dlen \ inc -- }
lastNFA 12 + 1stNFA
DO 12 -> inc \ usual length of an ivar
NxtL
i 6 + @ \ get ivars class pointer
dup ' Object =
IF ." DATA " drop \ This ivar is DATA
i lastNFA = \ If last ivar, can't subtract from next ivar
IF dlen \ computes # bytes
ELSE i 22 + w@ THEN
i 10 + w@ - .odata
ELSE
dup nfa id. \ This ivar may be nested
dup @width \ indexed?
dup IF 14 -> inc
4 ++> odata THEN \ (get past indexed overhead)
over ifa @ 3 pick 26 + > or \ nest?
deflgs 16 and lAnd \ supposed to be displaying nested?
IF 1 ++> tab .struct -1 ++> tab
ELSE dfa w@ .odata THEN
THEN
inc +LOOP
;
0 value snest
\ ( ^class -- ) print ivar data & indexed data (recursive from .ivars & self)
:f .struct
1 ++> snest
dup dfa w@ \ total length of object data
over sfa @ dfa w@ \ length of super class data
tab 0= over lAnd deflgs 08 and lAnd
IF 3 pick dup sfa @ dup nfa CR ." --" id. CR \ display super data
.struct nfa CR ." ==" id. CR
ELSE dup ++> odata THEN \ skip super data
- -dup \ total data minus super data
IF over ifa @ \ pointer to last ivar
3 pick 26 + \ pointer to first ivar
rot .ivars \ print ivar data
ELSE tab 0= IF .exp ." ( No ivars )" .nor CR THEN THEN
@width \ print indexed data if any
IF deflgs 32 and snest 0= lAnd
IF NxtL .exp ." --Indexed Data--" .nor
.idata
THEN
THEN
-1 ++> snest
;f
\ ( pfa -- ) display the data of an object
: deObj CR
dup here >
IF ." HEAP-OBJECT "
ELSE dup nfa id. THEN \ otherwise print object name
dup -> odata \ set start of data
.exp ." is an Object of Class: " .nor
cfa @ dup nfa id. \ print superclass name
-1 -> snest 0 -> tab
.struct \ print ivar data & indexed data
;
\ ( pfa -- ) decompile a module definition
: deModule { \ #imps -- }
." From " dup nfa id. ." Import{ "
dup 16 + w@ -> #imps 12 + @
#imps 1- 0 DO \ gather export words
dup pfa lfa @
LOOP
#imps 0 DO \ print export word names
id.
LOOP
." }"
;
0 constant con
0 variable vare
\ ( pfa -- pfa bool )
: ?isMod modCode over cfa (@) drop = ;
' does> 20 + constant doesCode
\ ( pfa -- ) setup for one of the decompilers: Colon, Class, Object, etc…
: (de) ?pause
dup -> start 0 -> nflgs 0 -> tab
dup cfa @ over = IF nfa id. .exp ." is a Code word" .nor CR exit THEN
?isObj IF deObj CR exit THEN
?isClass IF deClass CR exit THEN
?isMod IF deModule CR exit THEN
dup cfa @ ( pfa code )
dup colCode = over ' colP = or
IF drop CR ." : " dup .nfa deCol CR ." ; " CR exit THEN
CASE
over .nfa .exp ( pfa code )
valCode OF .bld ." is a Value " .nor 8+ dup .( @ dup .32-bit .) cr
?isobj IF (de) ELSE drop THEN ENDOF
fvalCode OF ." is an fValue" .nor drop ENDOF
impCFA OF ." is an Import word " .nor dup .( space @ >name id. .)
nflgs $ 40 and IF CR ." Immediate" THEN ENDOF
'code con OF ." is a Constant " .nor dup .( @ .32-bit .) ENDOF
'code vare OF ." is a Variable " .nor dup .( @ .32-bit .) ENDOF
vectCode OF .bld ." is a Vect " .nor 8+ dup .( @ -dup IF 4+ dup nfa space id. .) cr (de)
ELSE 0 . .) THEN ENDOF
svCode OF ." is a sysVect " .nor 8+ dup 4+
begin-dp @ rot @ + dup @ 0= IF drop dup THEN
dup .( @ 4+ dup nfa space id. ." ) … default "
swap dup .( @ >name space id. .) cr (de) ENDOF
doesCode OF @ latest BEGIN 2dup < WHILE pfa lfa @ REPEAT
." is a " id. ." definition" .nor drop ENDOF
\ OTHERWISE ( pfa code )
' (dodo) over 2+ @ =
IF 0 >R latest BEGIN 2dup < WHILE R> drop dup >R pfa lfa @ REPEAT
." is a " R> id. ." definition" .nor 2drop
ELSE
dup 4- @ over =
IF ." is an alias of " .nor nfa id.
ELSE ." is a MYSTERY" .nor drop THEN
THEN
ENDCASE
CR
;
\ ( str255 chr -- offs t OR f )
: charOf { adr chr -- }
0 \ bool
adr c@ 1+ 1
DO
adr i+ c@ chr = IF drop i 1- 1 leave THEN
LOOP
;
\ ( str -- nfa ) lookup module vocabulary if specified; else main dictionary
: dvoc { str -- }
str ascii | charOf
IF str over 1+ over c@ over - str rot + c! c! \ double string
str count + latest (find) 0= Abort" not found" drop
?isMod 0= Abort" not a module"
dup cfa execute \ get module into memory
8+ @ $ ffffff and
@ $ ffffff and \ get nfa of last word in module
ELSE latest THEN ;
\ decompile any yerk word or method
\ de' word[|module]
\ de' meth: class[|module]
: de'
@word dup c@ over + c@ ascii : =
IF dup count str255 drop hash \ method of a class
@word dup
dvoc (find) 0= Abort" not found" drop
?isClass 0= Abort" not a class"
dup -> start (findm) ." :M " buf255 count type 4+ deCol
CR ." ;M" CR
ELSE \ normal word
dup dvoc (find) 0= Abort" not found" drop
(de)
THEN ;
;Module